home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / tsh10.zip / TSH.C < prev    next >
Text File  |  1994-07-03  |  44KB  |  2,221 lines

  1. /*
  2.  *  tsh - "Troy's Shell" - a command line interface for Windows.
  3.  *
  4.  *  Copyright (C) 1994  Troy Rollo <troy@cbme.unsw.EDU.AU>
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21. #include <windows.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <fcntl.h>
  26. #include <dir.h>
  27. #include <dos.h>
  28. #include <sys/stat.h>
  29. #include <io.h>
  30. #include <time.h>
  31. #include <ctype.h>
  32. #include <errno.h>
  33. #include <toolhelp.h>
  34. #include <share.h>
  35. #include <sys/tkwin.h>
  36. #include <sys/tkern.h>
  37. #include <sys/tkexec.h>
  38. #include <sys/task.h>
  39. #include <sys/wait.h>
  40. #include <signal.h>
  41.  
  42.  
  43. char    *Months[] =
  44. {
  45.     "January",
  46.     "February",
  47.     "March",
  48.     "April",
  49.     "May",
  50.     "June",
  51.     "July",
  52.     "August",
  53.     "September",
  54.     "October",
  55.     "November",
  56.     "December"
  57. };
  58.  
  59. char    *Days[] =
  60. {
  61.     "Sunday",
  62.     "Monday",
  63.     "Tuesday",
  64.     "Wednesday",
  65.     "Thursday",
  66.     "Friday",
  67.     "Saturday"
  68. };
  69.  
  70. struct    redirection
  71. {
  72.     int    fd;
  73.     int    fdSource;
  74.     int    iMode;
  75.     char    *pchFile;
  76. };
  77.  
  78. struct    backend
  79. {
  80.     int    iTask;
  81.     struct backend *pbeNext;
  82. };
  83.  
  84. struct    backend *pbeList = 0;
  85.  
  86.  
  87. int parse_command(char const *s);
  88. char *pwd(void);
  89.  
  90. static char tmpbuf[2048];
  91. static char buf[2048] = {0};
  92. static char title[80] = "tsh";
  93. static unsigned instance = 0;
  94. static    HWND    hWnd = 0;
  95. static    HWND    hWndOA;
  96. static    HINSTANCE hInstance;
  97. static    HTASK    hTask;
  98. static    BOOL    bBreak = FALSE;
  99.  
  100.  
  101. #pragma argsused
  102. BOOL    CALLBACK _export EnumOldApp(HWND hThisWnd, LPARAM lParam)
  103. {
  104.     hWndOA = hThisWnd;
  105.     return TRUE;
  106. }
  107.  
  108. HTASK    GetTaskFromInstance(HINSTANCE hInst)
  109. {
  110.     TASKENTRY    te;
  111.  
  112.     te.dwSize = sizeof(TASKENTRY);
  113.     TaskFirst(&te);
  114.     do
  115.     {
  116.         if (te.hInst == hInst)
  117.             return te.hTask;
  118.     } while (TaskNext(&te));
  119.     return 0;
  120. }
  121.  
  122. HINSTANCE GetInstanceFromTask(HTASK hTask)
  123. {
  124.     TASKENTRY    te;
  125.  
  126.     te.dwSize = sizeof(TASKENTRY);
  127.     TaskFirst(&te);
  128.     do
  129.     {
  130.         if (te.hTask == hTask)
  131.             return te.hInst;
  132.     } while (TaskNext(&te));
  133.     return 0;
  134. }
  135.  
  136.  
  137. char    *BaseName(char *File)
  138. {
  139.     char    *c1;
  140.     char    *c2;
  141.  
  142.     c1 = strrchr(File, '\\');
  143.     c2 = strrchr(File, '/');
  144.     if (c1 || c2)
  145.     {
  146.         if (c1 > c2)
  147.             return c1+1;
  148.         else
  149.             return c2+1;
  150.     }
  151.     return File;
  152. }
  153.  
  154. #define    MAXTASKS    20
  155.  
  156. char    WhiteSpace[] = " \t";
  157. char    EmptyString[] = "";
  158.  
  159. struct    TaskInfo
  160. {
  161.     HTASK    hTask;
  162.     WORD    wStatus;
  163. };
  164.  
  165. #define    EF_BATCH    0x0001
  166.  
  167. struct    ExtTypes
  168. {
  169.     char    Ext[4];
  170.     char    Prog[13];
  171.     int    Exists;
  172.     int    Flags;
  173. } Extensions[80] =
  174. {
  175.     "EXE",    "",        0,    0,
  176.     "COM",    "",        0,    0,
  177.     "TSH",    "*",        0,    EF_BATCH,
  178.     "BAT",    "",        0,    0,
  179.     "PIF",    "",        0,    0,
  180.     "",    "",        0,    0
  181. };
  182.  
  183. BOOL    NewDead = FALSE;
  184.  
  185. struct    TaskInfo    Tasks[MAXTASKS];
  186.  
  187. void    FlushMessages(void)
  188. {
  189.     MSG    msg;
  190.  
  191.     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  192.     {
  193.         TranslateMessage(&msg);
  194.         DispatchMessage(&msg);
  195.     }
  196. }
  197.  
  198.  
  199. int    cmdnum = 0;
  200.  
  201. char    *prompt_names[3] = { "PS1", "PS2", "PS3" };
  202.  
  203. void    PutFormat(char *buffer, char const *format)
  204. {
  205.     char    *c;
  206.     char    const *tmp;
  207.     char    varname[20];
  208.  
  209.     c = buffer;
  210.     for (;*format;format++)
  211.     {
  212.         switch(*format)
  213.         {
  214.         case '!':
  215.             sprintf(c, "%d", cmdnum);
  216.             c+=strlen(c);
  217.             break;
  218.         case '~':
  219.             strcpy(c, pwd());
  220.             c+=strlen(c);
  221.             break;
  222.         case '$':
  223.             if (format[1]!='{')
  224.                 break;
  225.             tmp = ++format;
  226.             while (*format && *format != '}')
  227.                 format++;
  228.             if (!*format)
  229.             {
  230.                 format--;
  231.                 break;
  232.             }
  233.             strncpy(varname, tmp, format-tmp);
  234.             varname[format-tmp] = '\0';
  235.             if ((tmp = getenv(varname)) != 0)
  236.             {
  237.                 strcpy(c, tmp);
  238.                 c+=strlen(c);
  239.             }
  240.             break;
  241.         default:
  242.             *c++ = *format;
  243.             break;
  244.         }
  245.     }
  246.     *c = '\0';
  247. }
  248. void
  249. add_backend(int iTask)
  250. {
  251.     struct backend **ppbe;
  252.  
  253.     for (ppbe = &pbeList; *ppbe; ppbe = &(*ppbe)->pbeNext);
  254.     *ppbe = (struct backend *) malloc(sizeof(struct backend));
  255.     (*ppbe)->iTask = iTask;
  256.     (*ppbe)->pbeNext = 0;
  257. }
  258.  
  259. BOOL
  260. remove_backend(int iTask)
  261. {
  262.     struct backend **ppbe, *pbeTemp;
  263.  
  264.     for (ppbe = &pbeList; *ppbe; ppbe = &(*ppbe)->pbeNext)
  265.     {
  266.         if ((*ppbe)->iTask == iTask)
  267.         {
  268.             pbeTemp = *ppbe;
  269.             *ppbe = pbeTemp->pbeNext;
  270.             free(pbeTemp);
  271.             return TRUE;
  272.         }
  273.     }
  274.     return FALSE;
  275. }
  276.  
  277.  
  278.  
  279. void    show_prompt(int number)
  280. {
  281.     char    *format;
  282.     char    buffer[160];
  283.     char    *c;
  284.     char    *tmp;
  285.     char    varname[20];
  286.     struct    time timeval;
  287.     long    dateval;
  288.     struct  tm *gmt;
  289.  
  290.     c = buffer;
  291.     if ((format = getenv(prompt_names[number])) != 0)
  292.     {
  293.         PutFormat(buffer, format);
  294.     }
  295.     else
  296.     {
  297.         format = getenv("PROMPT");
  298.         for (;*format;format++)
  299.         {
  300.             if (*format == '$')
  301.             {
  302.                 switch(*++format)
  303.                 {
  304.                 case 'p':
  305.                     strcpy(c, pwd());
  306.                     c+=strlen(c);
  307.                     break;
  308.                 case 'q':
  309.                     *c++ = '=';
  310.                     break;
  311.                 case '$':
  312.                     *c++ = '$';
  313.                     break;
  314.                 case 't':
  315.                     gettime(&timeval);
  316.                     sprintf(c, "%02d:%02d:%02d.%02d",
  317.                         timeval.ti_hour,
  318.                         timeval.ti_min,
  319.                         timeval.ti_sec,
  320.                         timeval.ti_hund);
  321.                     c += strlen(c);
  322.                     break;
  323.                 case 'd':
  324.                     time(&dateval);
  325.                     gmt = gmtime(&dateval);
  326.                     sprintf(c, "%3.3s %02d-%02d-%04d",
  327.                         Days[gmt->tm_wday],
  328.                         gmt->tm_mon+1,
  329.                         gmt->tm_mday,
  330.                         gmt->tm_year+1900);
  331.                     c += strlen(c);
  332.                     break;
  333.                 case 'v':
  334.                     sprintf(c, "MS-DOS Version %d.%d", _osmajor, _osminor);
  335.                     c += strlen(c);
  336.                     break;
  337.                 case 'l':
  338.                     *c++ = '<';
  339.                     break;
  340.                 case 'g':
  341.                     *c++ = '>';
  342.                     break;
  343.                 case 's':
  344.                     *c++ = ';';
  345.                     break;
  346.                 case 'c':
  347.                     *c++ = ':';
  348.                     break;
  349.                 case 'r':
  350.                     *c++ = '\r';
  351.                     break;
  352.                 case '_':
  353.                     *c++ = '\n';
  354.                     break;
  355.                 case 'n':
  356.                     *c++ = 'A' + getdisk();
  357.                     break;
  358.                 case 'b':
  359.                     *c++ = '|';
  360.                     break;
  361.                 case 'e':
  362.                     *c++ = '\033';
  363.                     break;
  364.                 case 'h':
  365.                     *c++ = '\b';
  366.                     break;
  367.                 case '!':
  368.                     sprintf(c, "%d", cmdnum);
  369.                     c+=strlen(c);
  370.                     break;
  371.                 case '\0':
  372.                     format--;
  373.                 }
  374.             }
  375.             else
  376.                 (*c++ = *format);
  377.         }
  378.         *c = '\0';
  379.     }
  380.     printf("%s", buffer);
  381.     if (hWnd && (format = getenv("WS1")) != 0)
  382.     {
  383.         PutFormat(buffer, format);
  384.         SetWindowText(hWnd, buffer);
  385.     }
  386. }
  387.  
  388. #pragma argsused
  389. void
  390. IntCatcher(int nSig)
  391. {
  392.     bBreak = TRUE;
  393.     signal(SIGINT, IntCatcher);
  394. }
  395.  
  396.  
  397. #pragma argsused
  398. main(int argc, char **argv)
  399. {
  400.      int    i;
  401.     FILE    *fp;
  402.     long    wstatus;
  403.     short    pid;
  404.  
  405.     hTask = GetCurrentTask();
  406.     hInstance = GetInstanceFromTask(hTask);
  407.     for (i = 0; i<MAXTASKS; i++)
  408.         Tasks[i].hTask = 0;
  409.     if (tkern_is_device(0, "window"))
  410.         hWnd = (HWND) ioctl(0, WIOCGETHANDLE);
  411.     signal(SIGINT, IntCatcher);
  412.     
  413.     if ((fp = fopen("C:\\AUTOEXEC.TSH", "r")) != 0)
  414.     {
  415.         while (!bBreak && fgets(buf, 2048, fp))
  416.         {
  417.             buf[strlen(buf)-1] = '\0';
  418.             parse_command(buf);
  419.         }
  420.         fclose(fp);
  421.     }
  422.     while(1)
  423.     {
  424.         ++cmdnum;
  425.         while ((pid = waitpid(0, &wstatus , WNOHANG)) > 0)
  426.         {
  427.             if (remove_backend(pid))
  428.                 ;
  429.             else if (WIFEXITED(wstatus))
  430.                 printf("%d - Exit %d\n",
  431.                     (int) pid,
  432.                     (int) WEXITSTATUS(wstatus));
  433.             else if (WIFSTOPPED(wstatus))
  434.                 printf("%d - Stopped\n",
  435.                     (int) pid);
  436.             else
  437.                 printf("%d - Terminated (Signal %d)\n",
  438.                     (int) pid,
  439.                     (int) WTERMSIG(wstatus));
  440.         }
  441.         if (bBreak)
  442.         {
  443.             printf("\nInterrupt\n");
  444.             bBreak = FALSE;
  445.         }
  446.         show_prompt(0);
  447.         if (bBreak)
  448.             bBreak = FALSE;
  449.         if (!gets(buf))
  450.             break;
  451.         if (bBreak)
  452.             bBreak = FALSE;
  453.         parse_command(buf);
  454.     }
  455.     return 0;
  456. }
  457.  
  458. #pragma argsused
  459. char *pwd(void)
  460. {
  461.     static char buf[256];
  462.     char *s;
  463.  
  464.     return ((s = getcwd(buf, 255)) != 0) ? s : "invalid";
  465. }
  466.  
  467. #pragma argsused
  468. int do_pwd(int argc, char **argv)
  469. {
  470.     printf("Current directory is %s\n", pwd());
  471.     return 0;
  472. }
  473.  
  474. int do_chdrive(char *s)
  475. {
  476.     if (islower(*s))
  477.         *s=toupper(*s);
  478.     if (s[1] == ':')
  479.     {
  480.         setdisk(s[0] - 'A');
  481.         return 0;
  482.     }
  483.     else
  484.     {
  485.         return 1;
  486.     }
  487. }
  488.  
  489. int do_cd(int argc, char **argv)
  490. {
  491.     if (argc != 1)
  492.     {
  493.         printf("Usage: cd directory\n");
  494.         return 1;
  495.     }
  496.     if (argv[0][1] == ':')
  497.     {
  498.         // allow drives in here too
  499.         if (do_chdrive(argv[0]))
  500.             return 2;
  501.         argv[0] += 2;
  502.     }
  503.     if (*argv[0] && chdir(argv[0]))
  504.     {
  505.         printf("File not found\n");
  506.         return 3;
  507.     }
  508.     else
  509.         return 0;
  510. }
  511.  
  512. #define    DF_LONG    1
  513. #define    DF_SIZE    2
  514. #define    DF_ALL    4
  515. #define    DF_PC    8
  516. #define    DF_DIRONLY 16
  517. #define    DF_SPC 32
  518. #define    DF_RECUR 64
  519. #define    DF_DOS 128
  520.  
  521. void show_filename(char *directory, struct find_t *pinfo, unsigned Flags, unsigned FileNo)
  522. {
  523.     struct stat sbuf;
  524.     char    attributes[8];
  525.     char *c, *c2;
  526.     struct    tm *modtime;
  527.     char    path[256];
  528.     char    specialc;
  529.  
  530.     strcpy(path, directory);
  531.     if (path[0] && path[strlen(path) - 1] != '\\')
  532.         strcat(path, "\\");
  533.     strcat(path, pinfo->name);
  534.     stat(path, &sbuf);
  535.     c=attributes;
  536.     specialc = ' ';
  537.     switch(sbuf.st_mode&S_IFMT)
  538.     {
  539.     case S_IFDIR:
  540.         *c++='d';
  541.         specialc = '/';
  542.         break;
  543.     case S_IFIFO:
  544.         *c++='p';
  545.         break;
  546.     case S_IFCHR:
  547.         *c++='c';
  548.         break;
  549.     case S_IFBLK:
  550.         *c++='b';
  551.         break;
  552.     default:
  553.         *c++='-';
  554.         break;
  555.     }
  556.     modtime = localtime(&sbuf.st_mtime);
  557.     *c++=(sbuf.st_mode&S_IREAD)?'r':'-';
  558.     if ((sbuf.st_mode&S_IFMT) == S_IFDIR)
  559.         *c++ = 'w';
  560.     else
  561.         *c++=(sbuf.st_mode&S_IWRITE)?'w':'-';
  562.     if ((c2 = strrchr(pinfo->name, '.')) != 0 &&
  563.         !(strcmp(c2+1, "EXE") &&
  564.           strcmp(c2+1, "COM") &&
  565.           strcmp(c2+1, "BAT") &&
  566.           strcmp(c2+1, "DIR") &&
  567.           strcmp(c2+1, "TEX") &&
  568.           strcmp(c2+1, "TCO") &&
  569.           strcmp(c2+1, "TSH")))
  570.     {
  571.             specialc = '*';
  572.         *c++ = 'x';
  573.     }
  574.     else
  575.         *c++=(sbuf.st_mode&S_IEXEC)?'x':'-';
  576.     *c++=(pinfo->attrib & _A_SYSTEM)?'s':'-';
  577.     *c++=(pinfo->attrib & _A_HIDDEN)?'h':'-';
  578.     *c++=(pinfo->attrib & _A_ARCH)?'a':'-';
  579.     *c='\0';
  580.     if (!(sbuf.st_mode&S_IFDIR))
  581.         for (c=pinfo->name; *c; c++)
  582.             if (isupper(*c))
  583.                 *c=tolower(*c);
  584.     if (!(Flags & DF_PC))
  585.         specialc = ' ';
  586.     if (Flags & DF_DOS)
  587.     {
  588.             if (sbuf.st_mode&S_IFDIR)
  589.             {
  590.                 printf("%-12s <DIR>     %2d-%02d-%02d   %02d:%02d%c\n",
  591.                     pinfo->name, modtime->tm_mon+1, modtime->tm_mday,
  592.                     modtime->tm_year,
  593.                     (modtime->tm_hour==0)?12:(
  594.                 (modtime->tm_hour<12)?modtime->tm_hour:(modtime->tm_hour-12)),
  595.                 modtime->tm_min, (modtime->tm_hour<12)?'a':'p');
  596.             }
  597.             else
  598.             {
  599.                 printf("%-12s %9ld %2d-%02d-%02d   %02d:%02d%c\n",
  600.                 pinfo->name, pinfo->size,
  601.                 modtime->tm_mon+1, modtime->tm_mday,
  602.                     modtime->tm_year,
  603.                     (modtime->tm_hour==0)?12:(
  604.                 (modtime->tm_hour<12)?modtime->tm_hour:(modtime->tm_hour-12)),
  605.                 modtime->tm_min, (modtime->tm_hour<12)?'a':'p');
  606.         }
  607.     }
  608.     else if (Flags & DF_LONG)
  609.     {
  610.         printf(" %s %8ld %2d-%3.3s-%2.2d %02d:%02d %s%c\n", 
  611.             attributes, pinfo->size,
  612.             modtime->tm_mday, Months[modtime->tm_mon], modtime->tm_year,
  613.             modtime->tm_hour, modtime->tm_min, pinfo->name, specialc);
  614.     }
  615.     else
  616.     {
  617.         printf("%s%c%*.*s", pinfo->name, specialc,
  618.             14-strlen(pinfo->name), 14-strlen(pinfo->name), "                ");
  619.         if (FileNo%5 == 4)
  620.             putchar('\n');
  621.     }
  622. }
  623.  
  624. void    list_file(char *name, unsigned Flags)
  625. {
  626.     char dirname[80];
  627.     char wildcard[80];
  628.     unsigned attrib;
  629.     unsigned files;
  630.     unsigned long bytes;
  631.     struct find_t info;
  632.     struct stat sbuf;
  633.     
  634.     strcpy(dirname, name);
  635.     *BaseName(dirname) = '\0';
  636.     strcpy(wildcard, name);
  637.     if (strlen(wildcard) == 2 && wildcard[1] == ':')
  638.             strcat(wildcard, ".");
  639.     attrib = _A_NORMAL | _A_SUBDIR | _A_RDONLY;
  640.     if (Flags & DF_ALL)
  641.             attrib |= _A_SYSTEM | _A_HIDDEN;
  642.     if (!(Flags&DF_DIRONLY) &&
  643.             !strchr(wildcard, '?') &&
  644.             !strchr(wildcard, '*') &&
  645.         stat(wildcard, &sbuf) != -1 &&
  646.         (sbuf.st_mode & S_IFMT) == S_IFDIR)
  647.     {
  648.             if (wildcard[strlen(wildcard)-1] != '\\')
  649.             {
  650.                 strcat(wildcard, "\\");
  651.             strcpy(dirname, wildcard);
  652.         }
  653.         strcat(wildcard, "*.*");
  654.     }
  655.     files = 0;
  656.     if (_dos_findfirst(wildcard, attrib, &info) != 0)
  657.     {
  658.         printf("%s: File Not Found\n", wildcard);
  659.         return;
  660.     }
  661.     files = 0;
  662.     bytes = 0;
  663.     do
  664.     {
  665.         if (*info.name == '.' && !(Flags&DF_SPC))
  666.                 continue;
  667.            show_filename(dirname, &info, Flags, files);
  668.             files++;
  669.            bytes += info.size;
  670.     } while (!bBreak && _dos_findnext(&info) == 0);
  671.     if (!(Flags & (DF_DOS | DF_LONG)) && (files % 5))
  672.         putchar('\n');
  673.     printf("%5u File(s)\t%lu bytes\n", files, bytes);
  674.     return;
  675. }
  676.  
  677.  
  678. int do_std_dir(int argc, char **argv, unsigned Flags)
  679. {
  680.     struct find_t info;
  681.     unsigned long bytes;
  682.     unsigned attrib, files;
  683.     char *arg;
  684.     struct stat sbuf;
  685.  
  686.     while (argc && **argv == '-')
  687.     {
  688.         argc--;
  689.         arg = *argv++;
  690.            while (*++arg)
  691.             {
  692.                 switch(*arg)
  693.                 {
  694.                 case 'l':
  695.                     Flags |= DF_LONG;
  696.                     break;
  697.                 case 'a':
  698.                     Flags |= DF_ALL | DF_SPC;
  699.                     break;
  700.                 case 'A':
  701.                     Flags |= DF_ALL;
  702.                     break;
  703.                 case 's':
  704.                 Flags |= DF_SIZE;
  705.                     break;
  706.             case 'C':
  707.                     break; /* No op */
  708.                case 'd':
  709.                     Flags |= DF_DIRONLY;
  710.                     break;
  711.                 case 'F':
  712.                     Flags |= DF_PC;
  713.                     break;
  714.                 case 'R':
  715.                     Flags |= DF_RECUR;
  716.                     break;
  717.                 case 'D':
  718.                     Flags |= DF_DOS;
  719.                     break;
  720.             case 'W':
  721.             case 'w':
  722.                 Flags &= ~DF_DOS;
  723.             default:
  724.                 fprintf(stderr, "Usage: ls [-laAsCdFRDwW] [directories]\n");
  725.                 return 1;
  726.                 }
  727.             }
  728.         }
  729.     if (argc)
  730.         {
  731.         while (argc--)
  732.             list_file(*argv++, Flags);
  733.         }
  734.     else
  735.         list_file(".", Flags);
  736.     return 0;
  737. }
  738.  
  739. int do_dir(int argc, char **argv)
  740. {
  741.     return do_std_dir(argc, argv, 0);
  742. }
  743.  
  744. int do_dos_dir(int argc, char **argv)
  745. {
  746.     return do_std_dir(argc, argv, DF_DOS);
  747. }
  748.  
  749. int do_df(int argc, char **argv)
  750. {
  751.     struct    diskfree_t dtable;
  752.     char    drive;
  753.     long    nKbytes;
  754.  
  755.     printf("Drive      CSize      Total       Free      KB Free  %%Used\n");
  756.     if (argc)
  757.     {
  758.         while (argc--)
  759.         {
  760.             if (!_dos_getdiskfree(toupper(*argv[0]) - '@', &dtable))
  761.             {
  762.                 nKbytes = (long) dtable.avail_clusters *
  763.                       (long) dtable.sectors_per_cluster *
  764.                       (long) dtable.bytes_per_sector /
  765.                       1024l;
  766.                 printf("%c:    %7u    %7u    %7u %9lu  %5.1f\n",
  767.                     toupper(*argv[0]),
  768.                     dtable.sectors_per_cluster * dtable.bytes_per_sector,
  769.                     dtable.total_clusters,
  770.                     dtable.avail_clusters,
  771.                     nKbytes,
  772.                     ((float) dtable.total_clusters - dtable.avail_clusters) /
  773.                         dtable.total_clusters * 100.0);
  774.             }
  775.             else
  776.             {
  777.                 printf("Invalid drive specification\n");
  778.             }
  779.             argv++;
  780.         }
  781.         return 0;
  782.     }
  783.     for (drive = 3; drive < 26; drive++)
  784.     {
  785.         if (bBreak)
  786.             break;
  787.         if (_dos_getdiskfree(drive, &dtable))
  788.             continue;
  789.         nKbytes = (long) dtable.avail_clusters *
  790.               (long) dtable.sectors_per_cluster *
  791.               (long) dtable.bytes_per_sector /
  792.                   1024l;
  793.         printf("%c:    %7u    %7u    %7u %9lu  %5.1f\n",
  794.             (char) ('@' + drive),
  795.             dtable.sectors_per_cluster * dtable.bytes_per_sector,
  796.             dtable.total_clusters,
  797.             dtable.avail_clusters,
  798.             nKbytes,
  799.             (float) (((float) dtable.total_clusters - dtable.avail_clusters) /
  800.                 dtable.total_clusters * 100.0));
  801.     }
  802.     return 0;
  803. }
  804.  
  805.  
  806.  
  807. char *expand_wildcards(char *s)
  808. {
  809.     static    struct find_t info;
  810.     char wildcard[80];
  811.     static char directory[256];
  812.     static char filename[256];
  813.     unsigned attrib;
  814.     char *c1, *c2;
  815.  
  816.     if (s)
  817.     {
  818.         strcpy(wildcard, s);
  819.         strcpy(directory, wildcard);
  820.             if ((c1 = strrchr(directory, '/')) != 0 ||
  821.             (c2 = strrchr(directory, '\\')) != 0)
  822.             {
  823.             if (c1 > c2)
  824.                 c1[1] = '\0';
  825.             else
  826.                 c2[1] = '\0';
  827.         }
  828.         else
  829.             directory[0] = '\0';
  830.         if (! strchr(wildcard, '.'))
  831.             strcat(wildcard, "*.*");
  832.         attrib = _A_NORMAL | _A_SUBDIR | _A_RDONLY;
  833.         if (_dos_findfirst(wildcard, attrib, &info) != 0)
  834.             return NULL;
  835.         while (!strcmp(info.name, ".") || !strcmp(info.name, ".."))
  836.             if (_dos_findnext(&info))
  837.                 return NULL;
  838.     }
  839.     else
  840.     {
  841.         if (_dos_findnext(&info) != 0)
  842.             return NULL;
  843.     }
  844.     strcpy(filename, directory);
  845.     strcat(filename, info.name);
  846.     return filename;
  847. }
  848.  
  849.  
  850. char *FindExe(char *Path, char *Name, int *batch)
  851. {
  852.     static char ExecLine[256];
  853.     struct find_t info;
  854.     char wildcard[160];
  855.     int    i;
  856.     unsigned attrib;
  857.     char *Ext;
  858.     int r;
  859.     int HasExt = 0;
  860.  
  861.     *batch = 0;
  862.     for (i=0; *Extensions[i].Ext; i++)
  863.         Extensions[i].Exists = 0;
  864.     if (Path)
  865.     {
  866.         strcpy(wildcard, Path);
  867.         strcat(wildcard, "\\");
  868.     }
  869.     else
  870.         *wildcard = '\0';
  871.     strcat(wildcard, Name);
  872.     if (! strchr(Name, '.'))
  873.         strcat(wildcard, ".*");
  874.     else
  875.         HasExt = 1;
  876.     attrib = _A_NORMAL | _A_SUBDIR | _A_RDONLY;
  877.     for (r = _dos_findfirst(wildcard, attrib, &info); !r; r = _dos_findnext(&info))
  878.     {
  879.         if ((Ext = strchr(info.name, '.')) == 0)
  880.             continue;
  881.         Ext++;
  882.         for (i = 0; *Extensions[i].Ext; i++)
  883.         {
  884.             if (!stricmp(Extensions[i].Ext, Ext))
  885.             {
  886.                 Extensions[i].Exists = 1;
  887.                 break;
  888.             }
  889.         }
  890.         }
  891.     for (i = 0; *Extensions[i].Ext; i++)
  892.     {
  893.         if (Extensions[i].Exists)
  894.         {
  895.             if (*Extensions[i].Prog == '*')
  896.             {
  897.                 *batch = 1;
  898.                 *ExecLine = '\0';
  899.             }
  900.             else if (*Extensions[i].Prog)
  901.             {
  902.                 strcpy(ExecLine, Extensions[i].Prog);
  903.                 strcat(ExecLine, " ");
  904.             }
  905.             else
  906.                 *ExecLine = '\0';
  907.             if (Path)
  908.                 strcat(ExecLine, Path);
  909.             if (*ExecLine && ExecLine[strlen(ExecLine) - 1] != '\\')
  910.                 strcat(ExecLine, "\\");
  911.             strcat(ExecLine, Name);
  912.             if (!HasExt)
  913.             {
  914.                 strcat(ExecLine, ".");
  915.                 strcat(ExecLine, Extensions[i].Ext);
  916.             }
  917.             return ExecLine;
  918.         }
  919.     }
  920.     return NULL;
  921. }
  922.  
  923. char *FindPath(char *s, int *IsBatch)
  924. {
  925.     char    PathList[256];
  926.     char    *ExeName;
  927.     char    *PathElement;
  928.  
  929.     if (strchr(s, '/') || strchr(s, '\\'))
  930.     {
  931.         return FindExe(NULL, s, IsBatch);
  932.     }
  933.     strcpy(PathList, ".;");
  934.     strcat(PathList, getenv("PATH"));
  935.     for (PathElement = strtok(PathList, ";"); PathElement; PathElement = strtok(NULL, ";"))
  936.         if ((ExeName = FindExe(PathElement, s, IsBatch)) != 0)
  937.             return ExeName;
  938.     return NULL;
  939. }
  940.  
  941.  
  942. int do_activate(int argc, char **argv)
  943. {
  944.     HWND hWnd;
  945.  
  946.     while (argc--)
  947.     {
  948.         hWnd = FindWindow(NULL, *argv);
  949.         if (hWnd)
  950.         {
  951.             argv++;
  952.             BringWindowToTop(hWnd);
  953.             if (IsIconic(hWnd))
  954.                 ShowWindow(hWnd, SW_RESTORE);
  955.         }
  956.         else
  957.         {
  958.             fprintf(stderr, "%s: Window not found\n", argv);
  959.             return 1;
  960.         }
  961.     }
  962.     return 0;
  963. }
  964.  
  965. struct    alias
  966. {
  967.     struct    alias *next;
  968.     char    *name;
  969.     char    *text;
  970.     int    inuse;
  971. };
  972.  
  973. struct    alias    *alias_list = NULL;
  974.  
  975. int do_alias(int argc, char **argv)
  976. {
  977.     char    *c;
  978.     struct    alias *Alias;
  979.     int    i;
  980.     int    len;
  981.  
  982.     if (argc)
  983.     {
  984.         if (argc > 1)
  985.         {
  986.             for (len = 0, i = 1; i < argc; i++)
  987.                 len += strlen(argv[i]);
  988.             len += argc - 1;
  989.             Alias = malloc(sizeof(struct alias));
  990.             Alias->name = malloc(strlen(argv[0])+1);
  991.             Alias->text = malloc(len);
  992.             strcpy(Alias->name, argv[0]);
  993.             strcpy(Alias->text, argv[1]);
  994.             for (i = 2; i < argc; i++)
  995.             {
  996.                 strcat(Alias->text, " ");
  997.                 strcat(Alias->text, argv[i]);
  998.             }
  999.             Alias->inuse = 0;
  1000.             Alias->next = alias_list;
  1001.             alias_list = Alias;
  1002.         }
  1003.         else
  1004.         {
  1005.             for (Alias = alias_list; Alias!=NULL; Alias = Alias->next)
  1006.             {
  1007.                 if (!strcmp(Alias->name, argv[0]))
  1008.                 {
  1009.                     printf("%-10s %s\n", argv[0], Alias->text);
  1010.                     return 0;
  1011.                 }
  1012.             }
  1013.             fprintf(stderr, "No such alias: %s\n", argv[0]);
  1014.             return 1;
  1015.         }
  1016.     }
  1017.     else
  1018.     {
  1019.         for (Alias = alias_list; Alias; Alias = Alias->next)
  1020.             printf("%-10s %s\n", Alias->name, Alias->text);
  1021.     }
  1022.     return 0;
  1023. }
  1024.  
  1025. int    do_set(int argc, char **argv)
  1026. {
  1027.     char    *word;
  1028.     char    *value, envvar[160];
  1029.     char    *putable;
  1030.     int    i;
  1031.     char    **current;
  1032.  
  1033.     if (!argc)
  1034.     {
  1035.         for (current = environ; *current; current++)
  1036.             printf("%s\n", *current);
  1037.         return 0;
  1038.     }
  1039.     if (argc > 1)
  1040.     {
  1041.         sprintf(envvar, "%s=%s", argv[0], argv[1]);
  1042.         for (i = 2; i < argc; i++)
  1043.         {
  1044.             strcat(envvar, " ");
  1045.             strcat(envvar, argv[i]);
  1046.         }
  1047.         putable = malloc(strlen(envvar)+1);
  1048.         strcpy(putable, envvar);
  1049.         if (putenv(putable))
  1050.         {
  1051.             fprintf(stderr, "%s: %s\n", putable, sys_errlist[errno]);
  1052.             free(putable);
  1053.         }
  1054.     }
  1055.     else
  1056.     {
  1057.         if ((value = getenv(argv[0])) != 0)
  1058.         {
  1059.             printf("%s=%s\n", argv[0], value);
  1060.         }
  1061.         else
  1062.         {
  1063.             printf("No value for %s\n", argv[0]);
  1064.             return 1;
  1065.         }
  1066.     }
  1067.     return 0;
  1068. }
  1069.  
  1070. int    do_mkdir(int argc, char **argv)
  1071. {
  1072.     if (!argc)
  1073.     {
  1074.         fprintf(stderr, "Must specify a directory for mkdir\n");
  1075.         return 0;
  1076.     }
  1077.     while (!bBreak && argc--)
  1078.     {
  1079.         if (mkdir(*argv)==-1)
  1080.         {
  1081.             fprintf(stderr, "%s: %s\n", argv[0], sys_errlist[errno]);
  1082.             return 1;
  1083.         }
  1084.         argv++;
  1085.     }
  1086.     return 0;
  1087. }
  1088.  
  1089. int    do_rmdir(int argc, char **argv)
  1090. {
  1091.     if (!argc)
  1092.     {
  1093.         printf("Must specify a directory for rmdir\n");
  1094.         return 1;
  1095.     }
  1096.     while (!bBreak && argc--)
  1097.     {
  1098.         if (rmdir(*argv)==-1)
  1099.         {
  1100.             fprintf(stderr, "%s: %s\n", argv[0], sys_errlist[errno]);
  1101.             return 1;
  1102.         }
  1103.         argv++;
  1104.     }
  1105.     return 0;
  1106. }
  1107.  
  1108.  
  1109. int    do_del(int argc, char **argv)
  1110. {
  1111.     int    files;
  1112.     char    *sfile;
  1113.     int    error;
  1114.  
  1115.     if (!argc)
  1116.     {
  1117.         printf("Must specify files for del\n");
  1118.         return 1;
  1119.     }
  1120.     while (!bBreak && argc--)
  1121.     {
  1122.         for (files = 0, sfile = expand_wildcards(argv[0]);
  1123.              !bBreak && sfile;
  1124.              files++, sfile = expand_wildcards(NULL))
  1125.         {
  1126.             if (unlink(sfile)==-1)
  1127.             {
  1128.                 fprintf(stderr, "%s: %s\n", sfile, sys_errlist[errno]);
  1129.                 error = 1;
  1130.             }
  1131.         }
  1132.         if (!files)
  1133.         {
  1134.             fprintf(stderr, "%s: file not found\n", argv[0]);
  1135.             error = 1;
  1136.         }
  1137.         argv++;
  1138.     }
  1139.     return error;
  1140. }
  1141.  
  1142. int    do_type(int argc, char **argv)
  1143. {
  1144.     int    files;
  1145.     char    *sfile;
  1146.     FILE    *fp;
  1147.     char    Buffer[512];
  1148.     int    nread;
  1149.     int    error = 0;
  1150.  
  1151.     if (!argc)
  1152.     {
  1153.         fprintf(stderr, "Must specify files for type\n");
  1154.         return 1;
  1155.     }
  1156.     while (!bBreak && argc--)
  1157.     {
  1158.         for (files = 0, sfile = expand_wildcards(argv[0]);
  1159.              !bBreak && sfile;
  1160.              files++, sfile = expand_wildcards(NULL))
  1161.         {
  1162.             if ((fp = fopen(sfile, "r")) == NULL)
  1163.             {
  1164.                 fprintf(stderr, "%s: %s\n", sfile, sys_errlist[errno]);
  1165.                 error = 1;
  1166.                 continue;
  1167.             }
  1168.             while (!bBreak &&
  1169.                    (nread = fread(Buffer, 1, 512, fp)) > 0)
  1170.                 fwrite(Buffer, 1, nread, stdout);
  1171.             fclose(fp);
  1172.         }
  1173.         if (!files)
  1174.         {
  1175.             fprintf(stderr, "%s: file not found\n", argv[0]);
  1176.             error = 1;
  1177.         }
  1178.         argv++;
  1179.     }
  1180.     return error;
  1181. }
  1182.  
  1183. #pragma argsused
  1184. int    do_mem(int argc, char **argv)
  1185. {
  1186.     printf("%ldK free %d%% System Resources free\n",
  1187.         GetFreeSpace(0) / 1024,
  1188.         GetFreeSystemResources(GFSR_SYSTEMRESOURCES));
  1189.     return 0;
  1190. }
  1191.  
  1192. #pragma argsused
  1193. int    do_sysinfo(int argc, char **argv)
  1194. {
  1195.     DWORD    sys_info;
  1196.  
  1197.     sys_info = GetWinFlags();
  1198.  
  1199.     if (sys_info & WF_80x87)
  1200.         printf("Maths Coprocessor Present\n");
  1201.     if (sys_info & WF_CPU286)
  1202.         printf("80286 Processor\n");
  1203.     if (sys_info & WF_CPU386)
  1204.         printf("80386 Processor\n");
  1205.     if (sys_info & WF_CPU486)
  1206.         printf("i486 Processor\n");
  1207.     if (sys_info & WF_ENHANCED)
  1208.         printf("Enhanced Mode\n");
  1209.     if (sys_info & WF_STANDARD)
  1210.         printf("Standard Mode\n");
  1211.     if (sys_info & WF_PAGING)
  1212.         printf("System has paging\n");
  1213.     return 0;
  1214. }
  1215.  
  1216. /*
  1217.  * ps - list all running tasks with useful info. Note that while we are printing,
  1218.  * we may process messages. Once this happens, the task list may be in a new order.
  1219.  * consequently, we must build the list without displaying, and then display the
  1220.  * results from the list.
  1221.  */
  1222.  
  1223. extern    int    tkern_total_zombies(void);
  1224. extern    int    tkern_list_zombies(struct tk_process *, int);
  1225. extern    int    tkern_get_process(HTASK, struct tk_process *);
  1226.  
  1227. #pragma argsused
  1228. int    do_ps(int argc, char **argv)
  1229. {
  1230.     TASKENTRY    te;
  1231.     FARPROC lpfnEnumWndProc;
  1232.     char    TaskName[160];
  1233.     int    nTasks = 0;
  1234.     int    iTask = 0;
  1235.     TASKENTRY    *teList;
  1236.     char    **ppchTaskNames;
  1237.     struct    tk_process *pZombies;
  1238.     struct    tk_process *pProcesses;
  1239.     int    nZombies;
  1240.     int    i;
  1241.  
  1242.     te.dwSize = sizeof(TASKENTRY);
  1243.     printf("  PID  PPID Task  Parent Hinst Events StkSz Command\n");
  1244.        lpfnEnumWndProc = MakeProcInstance((FARPROC) EnumOldApp, hInstance);
  1245.     TaskFirst(&te);
  1246.     do
  1247.     {
  1248.         nTasks++;
  1249.     } while (TaskNext(&te));
  1250.     pProcesses = (struct tk_process *) malloc(sizeof(*pProcesses) * nTasks);
  1251.     nZombies = tkern_total_zombies();
  1252.     if (nZombies)
  1253.     {
  1254.         pZombies = (struct tk_process *) malloc(sizeof(*pZombies) * nZombies);
  1255.         tkern_list_zombies(pZombies, nZombies);
  1256.     }
  1257.     teList = (TASKENTRY *) malloc(sizeof(TASKENTRY) * nTasks);
  1258.     ppchTaskNames = malloc(sizeof(char *) * nTasks);
  1259.     memset(ppchTaskNames, 0, sizeof(char *) * nTasks);
  1260.     TaskFirst(&te);
  1261.     do
  1262.     {
  1263.         teList[iTask] = te;
  1264.         tkern_get_process(te.hTask, &pProcesses[iTask]);
  1265.         strcpy(TaskName, teList[iTask].szModule);
  1266.         if (!strcmp(TaskName, "WINOLDAP"))
  1267.         {
  1268.             hWndOA = 0;
  1269.             EnumTaskWindows(teList[iTask].hTask, (WNDENUMPROC) lpfnEnumWndProc, 0L);
  1270.             if (hWndOA)
  1271.                 GetWindowText(hWndOA, TaskName, 160);
  1272.             ppchTaskNames[iTask] = malloc(strlen(TaskName) + 1);
  1273.             strcpy(ppchTaskNames[iTask], TaskName);
  1274.         }
  1275.         iTask++;
  1276.     } while (TaskNext(&te));
  1277.     for (iTask = 0; iTask < nTasks; iTask++)
  1278.     {
  1279.         printf("%5d %5d %5d %5d  %5d %5d  %4x  %s\n",
  1280.             pProcesses[iTask].pid,
  1281.             pProcesses[iTask].pidParent,
  1282.             teList[iTask].hTask,
  1283.             teList[iTask].hTaskParent,
  1284.             teList[iTask].hInst,
  1285.             teList[iTask].wcEvents,
  1286.             teList[iTask].wStackBottom - teList[iTask].wStackTop,
  1287.             ppchTaskNames[iTask] ? ppchTaskNames[iTask] : teList[iTask].szModule);
  1288.         if (ppchTaskNames[iTask])
  1289.             free(ppchTaskNames[iTask]);
  1290.     }
  1291.     free(ppchTaskNames);
  1292.     free(teList);
  1293.     free(pProcesses);
  1294.     FreeProcInstance(lpfnEnumWndProc);
  1295.     if (nZombies)
  1296.     {
  1297.         for (i = 0; i < nZombies; i++)
  1298.             printf("%5d %5d                                 <defunct>\n",
  1299.                 (int) pZombies[i].pid,
  1300.                 (int) pZombies[i].pidParent);
  1301.         free(pZombies);
  1302.     }
  1303.     return 0;
  1304. }
  1305.  
  1306. int    do_kill(int argc, char **argv)
  1307. {
  1308.     int    signal;
  1309.     char    *flags;
  1310.     int    pid;
  1311.     BOOL    bError = FALSE;
  1312.  
  1313.     if (argc && *argv[0] == '-')
  1314.     {
  1315.         signal = atoi(argv[0]+1);
  1316.         argc--;
  1317.         argv++;
  1318.     }
  1319.     else
  1320.         signal = 14;
  1321.  
  1322.     if (!argc)
  1323.     {
  1324.         printf("Usage: kill [-#] task\n");
  1325.         return 1;
  1326.     }
  1327.     do
  1328.     {
  1329.         pid = atoi(argv[0]);
  1330.         if (kill(pid, signal) == -1)
  1331.             fprintf(stderr, "%d: %s\n", pid, sys_errlist[errno]);
  1332.         argv++;
  1333.     } while (--argc);
  1334.     return bError;
  1335. }
  1336.  
  1337. #pragma argsused
  1338. int    do_date(int argc, char **argv)
  1339. {
  1340.     long tm;
  1341.  
  1342.     time(&tm);
  1343.     printf("%s", ctime(&tm));
  1344.     return 0;
  1345. }
  1346.  
  1347. int    do_mv(int argc, char **argv)
  1348. {
  1349.     char    *dest;
  1350.     struct    stat sbuf;
  1351.     char    TmpBuffer[160];
  1352.     char    *FileStart;
  1353.     char    *sfile;
  1354.     int    files;
  1355.     int    error = 0;
  1356.  
  1357.     if ((argc > 2 && (stat(argv[argc-1], &sbuf) == -1 ||
  1358.               !(sbuf.st_mode & S_IFDIR))) ||
  1359.         argc < 2)
  1360.     {
  1361.         fprintf(stderr, "Usage: mv file1 file2\n    mv files directory\n");
  1362.         return 1;
  1363.     }
  1364.  
  1365.     dest = argv[argc-1];
  1366.     argc--;
  1367.     if (strlen(dest) == 2 && dest[1] == ':')
  1368.     {
  1369.         strcpy(TmpBuffer, dest);
  1370.         strcat(TmpBuffer, ".\\");
  1371.         dest = TmpBuffer;
  1372.         FileStart = TmpBuffer + strlen(TmpBuffer);
  1373.     }
  1374.     else if (stat(dest, &sbuf) != -1 && sbuf.st_mode & S_IFDIR)
  1375.     {
  1376.         strcpy(TmpBuffer, dest);
  1377.         if (TmpBuffer[strlen(TmpBuffer)-1] != '\\')
  1378.             strcat(TmpBuffer, "\\");
  1379.         FileStart = TmpBuffer + strlen(TmpBuffer);
  1380.         dest = TmpBuffer;
  1381.     }
  1382.     else
  1383.         FileStart = NULL;
  1384.     while (!bBreak && argc--)
  1385.     {
  1386.         for (files = 0, sfile = expand_wildcards(argv[0]);
  1387.              !bBreak && sfile;
  1388.              files++, sfile = expand_wildcards(NULL))
  1389.         {
  1390.             if (FileStart)
  1391.                 strcpy(FileStart, BaseName(sfile));
  1392.             if (rename(sfile, dest) == -1)
  1393.             {
  1394.                 fprintf(stderr, "%s: %s\n", sfile, sys_errlist[errno]);
  1395.                 error = 1;
  1396.             }
  1397.         }
  1398.         if (!files)
  1399.         {
  1400.             fprintf(stderr, "%s: File not found\n", argv[0]);
  1401.             error = 1;
  1402.         }
  1403.         argv++;
  1404.     }
  1405.     return error;
  1406. }
  1407.  
  1408. int    do_exit(int argc, char **argv)
  1409. {
  1410.     if (argc)
  1411.         exit(atoi(argv[0]));
  1412.     else
  1413.         exit(0);
  1414.     return -1;
  1415. }
  1416.  
  1417.  
  1418.  
  1419. int    do_copy(int argc, char **argv)
  1420. {
  1421.     char    *dest;
  1422.     struct    stat sbuf;
  1423.     char    TmpBuffer[160];
  1424.     char    Buffer[512];
  1425.     char    *FileStart;
  1426.     char    *sfile;
  1427.     int    files;
  1428.     int    fdin, fdout;
  1429.     int    nread;
  1430.     char    far    *lpchBuffer;
  1431.     HANDLE    hMem;
  1432.     unsigned uDate, uTime;
  1433.     int    error = 0;
  1434.  
  1435.     if ((argc > 2 && (stat(argv[argc-1], &sbuf) == -1 ||
  1436.               !(sbuf.st_mode & S_IFDIR))) ||
  1437.         argc < 2)
  1438.     {
  1439.         fprintf(stderr, "Usage: copy file1 file2\n    copy files directory\n");
  1440.         return 1;
  1441.     }
  1442.  
  1443.     dest = argv[argc-1];
  1444.     argc--;
  1445.     if (strlen(dest) == 2 && dest[1] == ':')
  1446.     {
  1447.         strcpy(TmpBuffer, dest);
  1448.         strcat(TmpBuffer, ".\\");
  1449.         dest = TmpBuffer;
  1450.         FileStart = TmpBuffer + strlen(TmpBuffer);
  1451.     }
  1452.     else if (stat(dest, &sbuf) != -1 && sbuf.st_mode & S_IFDIR)
  1453.     {
  1454.         strcpy(TmpBuffer, dest);
  1455.         if (TmpBuffer[strlen(TmpBuffer)-1] != '\\')
  1456.             strcat(TmpBuffer, "\\");
  1457.         FileStart = TmpBuffer + strlen(TmpBuffer);
  1458.         dest = TmpBuffer;
  1459.     }
  1460.     else
  1461.         FileStart = NULL;
  1462.     hMem = GlobalAlloc(GMEM_FIXED, 32000);
  1463.     lpchBuffer = GlobalLock(hMem);
  1464.     while (!bBreak && argc--)
  1465.     {
  1466.         for (files = 0, sfile = expand_wildcards(argv[0]);
  1467.              !bBreak && sfile;
  1468.              files++, sfile = expand_wildcards(NULL))
  1469.         {
  1470.             if (FileStart)
  1471.                 strcpy(FileStart, BaseName(sfile));
  1472.             if ((fdin = _lopen(sfile, READ)) == -1)
  1473.             {
  1474.                 fprintf(stderr, "Cannot open %s: %s\n", sfile, sys_errlist[errno]);
  1475.                 error = 1;
  1476.                 continue;
  1477.             }
  1478.             if ((fdout = _lcreat(dest, 0)) == -1)
  1479.             {
  1480.                 _lclose(fdin);
  1481.                 fprintf(stderr, "Cannot create %s: %s\n", dest, sys_errlist[errno]);
  1482.                 error = 1;
  1483.                 continue;
  1484.             }
  1485.             while (!bBreak && (nread = _lread(fdin, lpchBuffer, 32000)) != 0)
  1486.                 _lwrite(fdout, lpchBuffer, nread);
  1487.  
  1488.             _dos_getftime(fdin, &uDate, &uTime);
  1489.             _dos_setftime(fdout, uDate, uTime);
  1490.             _lclose(fdin);
  1491.             _lclose(fdout);
  1492.             if (bBreak)
  1493.                 unlink(dest);
  1494.         }
  1495.         if (!files)
  1496.         {
  1497.             fprintf(stderr, "%s: File not found\n", argv[0]);
  1498.             error = 1;
  1499.         }
  1500.         argv++;
  1501.     }
  1502.     GlobalUnlock(hMem);
  1503.     GlobalFree(hMem);
  1504.     return error;
  1505. }
  1506.  
  1507. int do_echo(int argc, char **argv)
  1508. {
  1509.     while (argc--)
  1510.     printf("%s ", *argv++);
  1511.     printf("\n");
  1512.     return 0;
  1513. }
  1514.  
  1515. #pragma argsused
  1516. int
  1517. do_true(int    argc,
  1518.     char    **argv)
  1519. {
  1520.     return 0;
  1521. }
  1522.  
  1523. #pragma argsused
  1524. int
  1525. do_false(int    argc,
  1526.     char    **argv)
  1527. {
  1528.     return 1;
  1529. }
  1530.  
  1531. struct
  1532. {
  1533.     char    *name;
  1534.     int    (*func)(int argc, char **argv);
  1535. } command_list[] = {
  1536.     ":",        do_true,
  1537.     "ACTIVATE",    do_activate,
  1538.     "ALIAS",    do_alias,
  1539.     "CD",        do_cd,
  1540.     "COPY",        do_copy,
  1541.     "DATE",        do_date,
  1542.     "DEL",        do_del,
  1543.     "DF",        do_df,
  1544.     "DIR",        do_dos_dir,
  1545.     "ECHO",        do_echo,
  1546.     "EXIT",        do_exit,
  1547.     "FALSE",    do_false,
  1548.     "KILL",        do_kill,
  1549.     "LS",        do_dir,
  1550.     "MEM",        do_mem,
  1551.     "MKDIR",    do_mkdir,
  1552.     "MV",        do_mv,
  1553.     "PS",        do_ps,
  1554.     "PWD",        do_pwd,
  1555.     "RMDIR",    do_rmdir,
  1556.     "SET",        do_set,
  1557.     "SYSINFO",    do_sysinfo,
  1558.     "TRUE",        do_true,
  1559.     "TYPE",        do_type,
  1560.     0,        0
  1561. };
  1562.  
  1563.  
  1564. #pragma argsused
  1565. int    RunBatch(char *FileName, char **argv, int argc)
  1566. {
  1567.     FILE    *fp;
  1568.     char    buf[2048];
  1569.  
  1570.     if ((fp = fopen(FileName, "r")) == 0)
  1571.     {
  1572.         while (!bBreak && fgets(buf, 2048, fp))
  1573.         {
  1574.             buf[strlen(buf)-1] = '\0';
  1575.             parse_command(buf);
  1576.         }
  1577.         fclose(fp);
  1578.         return 0;
  1579.     }
  1580.     else
  1581.     {
  1582.         printf("%s: %s\n", FileName, sys_errlist[errno]);
  1583.         return -1;
  1584.     }
  1585.  
  1586. }
  1587.  
  1588. int expand_alias(char const *cmd, char const *args, int *retval)
  1589. {
  1590.     char *expanded;
  1591.     struct    alias    *Alias;
  1592.  
  1593.     for (Alias = alias_list; Alias; Alias=Alias->next)
  1594.     {
  1595.         if (!stricmp(Alias->name, cmd))
  1596.         {
  1597.             if (Alias->inuse)
  1598.             {
  1599.                 /* Allow an alias to merely add arguments */
  1600.                 return FALSE;
  1601.             }
  1602.             expanded = malloc(strlen(Alias->text)+
  1603.                     strlen(args)+2);
  1604.             strcpy(expanded, Alias->text);
  1605.             if (args)
  1606.             {
  1607.                 strcat(expanded, " ");
  1608.                 strcat(expanded, args);
  1609.             }
  1610.             Alias->inuse = 1;
  1611.             *retval = parse_command(expanded);
  1612.             Alias->inuse = 0;
  1613.             free(expanded);
  1614.             return TRUE;
  1615.         }
  1616.     }
  1617.     return FALSE;
  1618. }
  1619.  
  1620. int do_command(    char    **orig_args,
  1621.         int    nArgs,
  1622.         BOOL    bWait,
  1623.         BOOL    bPipe,
  1624.         struct redirection *ar,
  1625.         int    nRedirections)
  1626. {
  1627.     char **args, **alloc_args;
  1628.     int ret; 
  1629.     int    i;
  1630.     int    iTask;
  1631.     char *PathElement;
  1632.     char *ExeName;
  1633.     char Command[256];
  1634.     HTASK hTask;
  1635.     int    GotTask;
  1636.     int IsBatch;
  1637.     HWND    focus;
  1638.     long    wstatus;
  1639.     int    fdSource[3];
  1640.  
  1641.     if (!nArgs)
  1642.         return 0;    /* Null command always succeeds */
  1643.  
  1644.     args = alloc_args = malloc(sizeof(*args) * (nArgs + 1));
  1645.     memcpy(args, orig_args, sizeof(*args) * (nArgs + 1));
  1646.  
  1647.     /* Check for a drive change directive */
  1648.  
  1649.     if (nArgs == 1 &&
  1650.         (strlen(args[0]) == 2) &&
  1651.         (args[0][1] == ':'))     // Change Drive:
  1652.         return do_chdrive(args[0]);
  1653.  
  1654.     /* Check for builtin commands */
  1655.  
  1656.     for (i = 0; command_list[i].name; i++)
  1657.         if (!stricmp(command_list[i].name, args[0]))
  1658.             return (*command_list[i].func)(nArgs-1, args+1);
  1659.  
  1660.  
  1661.     NewDead = 0;
  1662.     strcpy(tmpbuf, ".;");
  1663.     strcat(tmpbuf, getenv("PATH"));
  1664.     strupr(args[0]);
  1665.     if ((ExeName = FindPath(args[0], &IsBatch)) != 0)
  1666.     {
  1667.         if (IsBatch)
  1668.         {
  1669.             ret = RunBatch(ExeName, args+1, nArgs-1);
  1670.         }
  1671.         else
  1672.         {
  1673.             *Command = 0;
  1674.             while (--nArgs)
  1675.             {
  1676.                 if (*Command)
  1677.                     strcat(Command, " ");
  1678.                 ++args;
  1679.                 if (strchr(*args, ' ') ||
  1680.                     strchr(*args, '\t'))
  1681.                 {
  1682.                     strcat(Command, "\"");
  1683.                     strcat(Command, *args);
  1684.                     strcat(Command, "\"");
  1685.                 }
  1686.                 else
  1687.                     strcat(Command, *args);
  1688.             }
  1689.             for (i = 0; i < nRedirections; i++)
  1690.             {
  1691.                 if (ar[i].fdSource != -1)
  1692.                 {
  1693.                     fdSource[i] = dup(ar[i].fdSource);
  1694.                     if (fdSource[i] == -1)
  1695.                         fprintf(stderr, "%d: %s\n",
  1696.                             ar[i].fdSource,
  1697.                             sys_errlist[errno]);
  1698.                 }
  1699.                 else
  1700.                 {
  1701.                     fdSource[i] = open(    ar[i].pchFile,
  1702.                                 ar[i].iMode,
  1703.                                 0666);
  1704.                     if (fdSource[i] == -1)
  1705.                         fprintf(stderr, "%s: %s\n",
  1706.                             ar[i].pchFile,
  1707.                             sys_errlist[errno]);
  1708.                 }
  1709.                 if (fdSource[i] == -1)
  1710.                 {
  1711.                     while (i > 0)
  1712.                         close(fdSource[--i]);
  1713.                     free(alloc_args);
  1714.                     return -1;
  1715.                 }
  1716.             }
  1717.             iTask = fork();
  1718.             switch(iTask)
  1719.             {
  1720.             case 0:
  1721.                 for (i = 0; i < nRedirections; i++)
  1722.                 {
  1723.                     if (dup2(fdSource[i], ar[i].fd) == -1)
  1724.                     {
  1725.                         fprintf(stderr, "dup2: %s\n", sys_errlist[errno]);
  1726.                     }
  1727.                     close(fdSource[i]);
  1728.                 }
  1729.                 execv_ext(Command, ExeName, orig_args);
  1730.                 break;
  1731.  
  1732.             case -1:
  1733.                 fprintf(stderr, "%s: %s\n", ExeName, sys_errlist[errno]);
  1734.                 ret = -1;
  1735.                 break;
  1736.  
  1737.             default:
  1738.                 if (bWait)
  1739.                 {
  1740.                     waitpid(iTask, &wstatus, 0);
  1741.                     if (WIFEXITED(wstatus))
  1742.                         ret = WEXITSTATUS(wstatus);
  1743.                     else
  1744.                         ret = -1;
  1745.                 }
  1746.                 else if (bPipe)
  1747.                 {
  1748.                     add_backend(iTask);
  1749.                     ret = 0;
  1750.                 }
  1751.                 else
  1752.                 {
  1753.                     ret = 0;
  1754.                 }
  1755.                 break;
  1756.             }
  1757.             for (i = 0; i < nRedirections; i++)
  1758.             {
  1759.                 close(fdSource[i]);
  1760.             }
  1761.         }
  1762.     }
  1763.     else
  1764.     {
  1765.         ret = -2;
  1766.         fprintf(stderr, "%s: File not found\n", args[0]);
  1767.     }
  1768.     free(alloc_args);
  1769.     return ret;
  1770. }
  1771.  
  1772. char    const *FindMatch(char const *buffer, char match)
  1773. {
  1774.     for (buffer++; *buffer; buffer++)
  1775.     {
  1776.         if (*buffer == match)
  1777.             return buffer;
  1778.         if (*buffer == '\\' && buffer[1])
  1779.             buffer++;
  1780.     }
  1781.     return 0;
  1782. }
  1783.  
  1784.  
  1785. BOOL    IsEscapable(char c)
  1786. {
  1787.     return (c == '\\' || c == '\'' || c == '"' ||
  1788.         c == ';' || c == ' ' || c == '\t');
  1789. }
  1790.  
  1791. #define    ARG_CHUNK    64
  1792.  
  1793. #define CALC_SIZE(x) (((x)-1)-((x)-1)%ARG_CHUNK+ARG_CHUNK)
  1794.  
  1795. #pragma argsused
  1796. void    CopyTo(char **arg, char const *data, int chars, int dosubs)
  1797. {
  1798.     int    len;
  1799.     int    size;
  1800.     int    newlen;
  1801.     int    newsize;
  1802.     char    *newarg;
  1803.  
  1804.     if (!*arg)
  1805.     {
  1806.         size = 0;
  1807.         len = 1;
  1808.     }
  1809.     else
  1810.     {
  1811.         len = strlen(*arg) + 1;
  1812.         size = CALC_SIZE(len);
  1813.     }
  1814.     newlen = len + chars;
  1815.     newsize = CALC_SIZE(newlen);
  1816.     if (newsize != size)
  1817.     {
  1818.         newarg = malloc(newsize);
  1819.         if (*arg)
  1820.         {
  1821.             memcpy(newarg, arg, len);
  1822.             free(*arg);
  1823.         }
  1824.         *arg = newarg;
  1825.     }
  1826.     memcpy(*arg + len - 1, data, chars);
  1827.     (*arg)[newlen-1] = '\0';
  1828. }
  1829.  
  1830. void    FreeArgs(char **args, int nArgs)
  1831. {
  1832.     int    i;
  1833.  
  1834.     for (i = 0; i < nArgs; i++)
  1835.     {
  1836.         free(args[i]);
  1837.         args[i] = 0;
  1838.     }
  1839. }
  1840.  
  1841. void    FinishArg(char **arg)
  1842. {
  1843.     int    len;
  1844.     int    size;
  1845.     char    *newarg;
  1846.  
  1847.     len = strlen(*arg) + 1;
  1848.     size = CALC_SIZE(len);
  1849.     if (size == len)
  1850.         return;
  1851.     newarg = malloc(len);
  1852.     memcpy(newarg, *arg, len);
  1853.     free(*arg);
  1854.     *arg = newarg;
  1855. }
  1856.  
  1857. #define    TOKEN_ENDCOMMAND    ((unsigned) 0x8001)
  1858. #define    TOKEN_BGCOMMAND        ((unsigned) 0x8002)
  1859. #define    TOKEN_REDIRFROM        ((unsigned) 0x8003)
  1860. #define    TOKEN_REDIRTO        ((unsigned) 0x8004)
  1861. #define    TOKEN_APPENDTO        ((unsigned) 0x8005)
  1862. #define    TOKEN_FDFROM        ((unsigned) 0x8006)
  1863. #define    TOKEN_FDTO        ((unsigned) 0x8007)
  1864. #define    TOKEN_PIPE        ((unsigned) 0x8008)
  1865.  
  1866. #define    TOKEN_SPECIAL        ((unsigned) 0x8000)
  1867. #define    TOKEN_ERROR        ((unsigned) 0xFFFF)
  1868. #define    TOKEN_NONE        ((unsigned) 0x0000)
  1869. #define    TOKEN_OK        ((unsigned) 0x0001)
  1870.  
  1871. static    char    const achTokenChars[] =
  1872. { ";&<>|" };
  1873.  
  1874. struct token_information
  1875. {
  1876.     char    *pchToken;
  1877.     int    nToken;
  1878. };
  1879.  
  1880. static struct token_information ati[] =
  1881. {
  1882.     { ">&",    TOKEN_FDTO    },
  1883.     { "<&",    TOKEN_FDFROM    },
  1884.     { ">>",    TOKEN_APPENDTO    },
  1885.     { ">",    TOKEN_REDIRTO    },
  1886.     { "<",    TOKEN_REDIRFROM    },
  1887.     { "&",    TOKEN_BGCOMMAND    },
  1888.     { ";",    TOKEN_ENDCOMMAND },
  1889.     { "|",    TOKEN_PIPE    },
  1890.     { 0,    0        }
  1891. };
  1892.  
  1893. unsigned GetArg(char const    **pchString,
  1894.         char        **arg,
  1895.         BOOL        *bRunOn)
  1896. {
  1897.     int    i;
  1898.     int    nLen;
  1899.     char    const *c;
  1900.     char    const *end;
  1901.  
  1902.     *bRunOn = FALSE;
  1903.     c = *pchString;
  1904.     while (isspace(*c))
  1905.         c++;
  1906.     if (!*c)
  1907.     {
  1908.         *bRunOn = FALSE;
  1909.         return TOKEN_NONE;
  1910.     }
  1911.     if (strchr(achTokenChars, *c))
  1912.     {
  1913.         *bRunOn = FALSE;
  1914.         for (i = 0; ati[i].nToken; i++)
  1915.         {
  1916.             nLen = strlen(ati[i].pchToken);
  1917.             if (!strncmp(ati[i].pchToken, c, nLen))
  1918.             {
  1919.                 *pchString = c + nLen;
  1920.                 return ati[i].nToken;
  1921.             }
  1922.         }
  1923.         /* It is impossible to get here */
  1924.         *(char *) 0 = 0;
  1925.     }
  1926.     for (; *c!='\0'; c++)
  1927.     {
  1928.         if (isspace(*c))
  1929.         {
  1930.             FinishArg(arg);
  1931.             *bRunOn = FALSE;
  1932.             *pchString = c;
  1933.             return TOKEN_OK;
  1934.         }
  1935.         if (strchr(achTokenChars, *c))
  1936.         {
  1937.             *bRunOn = TRUE;
  1938.             FinishArg(arg);
  1939.             *pchString = c;
  1940.             return TOKEN_OK;
  1941.         }
  1942.         switch(*c) 
  1943.         {
  1944.         case '"':
  1945.         case '\'':
  1946.             end = FindMatch(c, *c);
  1947.             if (!end)
  1948.             {
  1949.                 fprintf(stderr, "Unterminated %c\n", *c);
  1950.                 if (*arg)
  1951.                 {
  1952.                     free(*arg);
  1953.                     *arg = 0;
  1954.                 }
  1955.                 return TOKEN_ERROR;
  1956.             }
  1957.             CopyTo(arg, c+1, end - c - 1, (*c == '"'));
  1958.             c = end;    
  1959.             break;
  1960.  
  1961.         case '\\':
  1962.             if (IsEscapable(c[1]))
  1963.             {
  1964.                 CopyTo(arg, ++c, 1, 0);
  1965.                 break;
  1966.             }
  1967.         default:
  1968.             CopyTo(arg, c, 1, 0);
  1969.             break;
  1970.         }
  1971.     }
  1972.     *bRunOn = FALSE;
  1973.     *pchString = c;
  1974.     FinishArg(arg);
  1975.     return TOKEN_OK;
  1976. }
  1977.  
  1978. void    free_redirections(    struct redirection *ar,
  1979.                 int    nRedirections)
  1980. {
  1981.     int    i;
  1982.  
  1983.     for (i = 0; i < nRedirections; i++)
  1984.     {
  1985.         if (ar[i].pchFile)
  1986.             free(ar[i].pchFile);
  1987.     }
  1988. }
  1989.  
  1990. void    cleanup(    char    *pchArg,
  1991.             char    **ppchArgs,
  1992.             int    nUsed,
  1993.             struct    redirection *ar,
  1994.             int    nRedirections,
  1995.             int    pfd[2])
  1996. {
  1997.     if (pchArg)
  1998.         free(pchArg);
  1999.     FreeArgs(ppchArgs, nUsed);
  2000.     free(ppchArgs);
  2001.     free_redirections(ar, nRedirections);
  2002.     if (pfd[0] != -1)
  2003.         close(pfd[0]);
  2004. }
  2005.  
  2006. int    parse_command(    char    const *pchCmd)
  2007. {
  2008.     char *c, *c2, *end;
  2009.     char    **args;
  2010.     char    *pchArg;
  2011.     int    nUsed;
  2012.     int    fdNow;
  2013.     int    i;
  2014.     int    retval;
  2015.     struct redirection ar[3];
  2016.     int    nRedirections = 0;
  2017.     unsigned nToken, nFileToken;
  2018.     BOOL    bRunOn = FALSE;
  2019.     BOOL    bLastRunOn;
  2020.     BOOL    bNonDigit;
  2021.     int    nFile;
  2022.     int    pfd[2];
  2023.     int    fdOldPipe;
  2024.  
  2025.     pfd[0] = pfd[1] = -1;
  2026.     args = malloc(50 * sizeof(char *));
  2027.     memset(args, 0, sizeof(*args) * 50);
  2028.     nUsed = 0;
  2029.     while(!bBreak)
  2030.     {
  2031.         bLastRunOn = bRunOn;
  2032.         pchArg = 0;
  2033.         nToken = GetArg(&pchCmd, &pchArg, &bRunOn);
  2034.         switch (nToken)
  2035.         {
  2036.         case TOKEN_NONE:
  2037.         case TOKEN_ENDCOMMAND:
  2038.         case TOKEN_BGCOMMAND:
  2039.         case TOKEN_PIPE:
  2040.             if (nUsed)
  2041.             {
  2042.                 fdOldPipe = pfd[0];
  2043.                 if (nToken == TOKEN_PIPE)
  2044.                 {
  2045.                     for (i = 0; i < nRedirections; i++)
  2046.                     {
  2047.                         if (ar[i].fd == 1)
  2048.                         {
  2049.                             fprintf(stderr, "Ambiguous redirection\n");
  2050.                             cleanup(pchArg, args, nUsed, ar, nRedirections, pfd);
  2051.                             return -1;
  2052.                         }
  2053.                     }
  2054.                     if (pipe(pfd) == -1)
  2055.                     {
  2056.                         fprintf(stderr, "pipe: %s\n", sys_errlist[errno]);
  2057.                         cleanup(pchArg, args, nUsed, ar, nRedirections, pfd);
  2058.                         return -1;
  2059.                     }
  2060.                     ar[nRedirections].fd = 1;
  2061.                     ar[nRedirections].fdSource = pfd[1];
  2062.                     ar[nRedirections].pchFile = 0;
  2063.                     nRedirections++;
  2064.                 }
  2065.                 else
  2066.                 {
  2067.                     pfd[0] = pfd[1] = -1;
  2068.                 }
  2069.                 retval = do_command(args, nUsed,
  2070.                         (nToken == TOKEN_BGCOMMAND ||
  2071.                          nToken == TOKEN_PIPE) ?
  2072.                             FALSE : TRUE,
  2073.                         (nToken == TOKEN_PIPE) ?
  2074.                             TRUE : FALSE,
  2075.                         ar, nRedirections);
  2076.                 FreeArgs(args, nUsed);
  2077.                 nUsed = 0;
  2078.                 free_redirections(ar, nRedirections);
  2079.                 nRedirections = 0;
  2080.                 if (nToken == TOKEN_PIPE)
  2081.                 {
  2082.                     close(pfd[1]);
  2083.                     ar[nRedirections].fd = 0;
  2084.                     ar[nRedirections].fdSource = pfd[0];
  2085.                     ar[nRedirections].pchFile = 0;
  2086.                     nRedirections++;
  2087.                 }
  2088.                 if (fdOldPipe != -1)
  2089.                     close(fdOldPipe);
  2090.             }
  2091.             else
  2092.             {
  2093.                 FreeArgs(args, nUsed);
  2094.                 free(args);
  2095.                 free_redirections(ar, nRedirections);
  2096.                 return retval;
  2097.             }
  2098.             break;
  2099.  
  2100.         case TOKEN_OK:
  2101.             args[nUsed++] = pchArg;
  2102.             if (nUsed == 1 &&
  2103.                expand_alias(args[0], pchCmd, &retval))
  2104.             {
  2105.                 FreeArgs(args, nUsed);
  2106.                 free(args);
  2107.                 free_redirections(ar, nRedirections);
  2108.                 return retval;
  2109.             }
  2110.             break;
  2111.  
  2112.         case TOKEN_FDTO:
  2113.         case TOKEN_APPENDTO:
  2114.         case TOKEN_REDIRTO:
  2115.         case TOKEN_REDIRFROM:
  2116.         case TOKEN_FDFROM:
  2117.             nFileToken = GetArg(&pchCmd, &pchArg, &bRunOn);
  2118.             if (nFileToken != TOKEN_OK)
  2119.             {
  2120.                 fprintf(stderr, "Redirection syntax error\n");
  2121.                 cleanup(pchArg, args, nUsed, ar, nRedirections, pfd);
  2122.                 return -1;
  2123.             }
  2124.             bRunOn = FALSE;
  2125.             nFile = -1;
  2126.             if (bLastRunOn)
  2127.             {
  2128.                 bNonDigit = FALSE;
  2129.                 for (i = 0; args[nUsed - 1][i]; i++)
  2130.                 {
  2131.                     if (!isdigit(args[nUsed - 1][i]))
  2132.                     {
  2133.                         bNonDigit = TRUE;
  2134.                         break;
  2135.                     }
  2136.                 }
  2137.                 if (!bNonDigit && args[nUsed - 1][0])
  2138.                 {
  2139.                     nFile = atoi(args[nUsed - 1]);
  2140.                     free(args[--nUsed]);
  2141.                     args[nUsed] = 0;
  2142.                     if (nFile > 2)
  2143.                     {
  2144.                         fprintf(stderr, "Silly redirection\n");
  2145.                         cleanup(pchArg, args, nUsed, ar, nRedirections, pfd);
  2146.                         return -1;
  2147.                     }
  2148.                 }
  2149.             }
  2150.             if (nFile == -1)
  2151.             {
  2152.                 switch(nToken)
  2153.                 {
  2154.                 case TOKEN_FDTO:
  2155.                 case TOKEN_APPENDTO:
  2156.                 case TOKEN_REDIRTO:
  2157.                     nFile = 1;
  2158.                     break;
  2159.  
  2160.                 case TOKEN_REDIRFROM:
  2161.                 case TOKEN_FDFROM:
  2162.                     nFile = 2;
  2163.                     break;
  2164.                 }
  2165.             }
  2166.             for (i = 0; i < nRedirections; i++)
  2167.             {
  2168.                 if (ar[i].fd == nFile)
  2169.                 {
  2170.                     fprintf(stderr, "Ambiguous redirection\n");
  2171.                     cleanup(pchArg, args, nUsed, ar, nRedirections, pfd);
  2172.                     return -1;
  2173.                 }
  2174.             }
  2175.             ar[nRedirections].fd = nFile;
  2176.             switch(nToken)
  2177.             {
  2178.             case TOKEN_FDFROM:
  2179.             case TOKEN_FDTO:
  2180.                 ar[nRedirections].pchFile = 0;
  2181.                 ar[nRedirections].fdSource = atoi(pchArg);
  2182.                 free(pchArg);
  2183.                 break;
  2184.  
  2185.             case TOKEN_APPENDTO:
  2186.             case TOKEN_REDIRTO:
  2187.             case TOKEN_REDIRFROM:
  2188.                 ar[nRedirections].pchFile = pchArg;
  2189.                 ar[nRedirections].fdSource = -1;
  2190.                 break;
  2191.             }
  2192.             switch(nToken)
  2193.             {
  2194.             case TOKEN_REDIRFROM:
  2195.             case TOKEN_FDFROM:
  2196.                 ar[nRedirections].iMode = O_RDONLY;
  2197.                 break;
  2198.  
  2199.             case TOKEN_REDIRTO:
  2200.             case TOKEN_FDTO:
  2201.                 ar[nRedirections].iMode = O_WRONLY | O_CREAT | O_TRUNC;
  2202.                 break;
  2203.  
  2204.             case TOKEN_APPENDTO:
  2205.                 ar[nRedirections].iMode = O_WRONLY | O_CREAT | O_APPEND;
  2206.                 break;
  2207.             }
  2208.             nRedirections++;
  2209.             break;
  2210.  
  2211.         case TOKEN_ERROR:
  2212.             cleanup(pchArg, args, nUsed, ar, nRedirections, pfd);
  2213.             return -1;
  2214.         }
  2215.     }
  2216.     cleanup(pchArg, args, nUsed, ar, nRedirections, pfd);
  2217.     return -1;
  2218. }
  2219.  
  2220.  
  2221.